package com.zwh.admin.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zwh.admin.entity.Permission;
import com.zwh.admin.entity.User;
import com.zwh.admin.helper.MemuHelper;
import com.zwh.admin.helper.PermissionHelper;
import com.zwh.admin.mapper.PermissionMapper;
import com.zwh.admin.service.PermissionService;
import com.zwh.admin.service.UserService;
import com.zwh.admin.entity.RolePermission;

import com.zwh.admin.service.RolePermissionService;
import com.zwh.exception_handler.ServerException;


/**
 * <p>
 * 权限 服务实现类
 * </p>
 *
 * @author testjava
 * @since 2020-01-12
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

    @Autowired
    private RolePermissionService rolePermissionService;

    @Autowired
    private UserService userService;

    //获取全部菜单
    @Override
    public List<Permission> queryAllMenu() {

        QueryWrapper<Permission> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");
        List<Permission> permissionList = baseMapper.selectList(wrapper);

        List<Permission> result = bulid(permissionList);

        return result;
    }

    /**
     * 根据角色获取菜单
     * 获取的菜单拥有层次结构
     *
     * @param roleId
     * @return
     */
    @Override
    public List<Permission> selectAllMenu(String roleId) {
        //根据id升序查询所有菜单
        List<Permission> allPermissionList = baseMapper.selectList(
                new QueryWrapper<Permission>().orderByAsc("CAST(id AS SIGNED)"));

        //根据角色id获取角色权限
        List<RolePermission> rolePermissionList = rolePermissionService.list(
                new QueryWrapper<RolePermission>().eq("role_id", roleId));
        //转换给角色id与角色权限对应Map对象
        List<String> permissionIdList = rolePermissionList.stream().map(e -> e.getPermissionId()).collect(Collectors.toList());
        allPermissionList.forEach(permission -> {
            if (permissionIdList.contains(permission.getId())) {
                permission.setSelect(true);
            } else {
                permission.setSelect(false);
            }
        });

//        //遍历所有菜单
//        for (int i = 0; i < allPermissionList.size(); i++) {
//            Permission permission = allPermissionList.get(i);
//            for (int m = 0; m < rolePermissionList.size(); m++) {
//                RolePermission rolePermission = rolePermissionList.get(m);
//                //选中该角色对应的所有菜单
//                if (rolePermission.getPermissionId().equals(permission.getId())) {
//                    permission.setSelect(true);
//                }
//            }
//        }

        //将 角色对应的菜单 封装成 层次结构 的 菜单
        List<Permission> permissionList = bulid(allPermissionList);
        return permissionList;
    }

    //给角色分配权限
    @Override
    public void saveRolePermissionRealtionShip(String roleId, String[] permissionIds) {

        rolePermissionService.remove(new QueryWrapper<RolePermission>().eq("role_id", roleId));


        List<RolePermission> rolePermissionList = new ArrayList<>();
        for (String permissionId : permissionIds) {
            if (StringUtils.isEmpty(permissionId)) {
                continue;
            }

            RolePermission rolePermission = new RolePermission();
            rolePermission.setRoleId(roleId);
            rolePermission.setPermissionId(permissionId);
            rolePermissionList.add(rolePermission);
        }
        rolePermissionService.saveBatch(rolePermissionList);
    }

    //递归删除菜单
    @Override
    public void removeChildById(String id) {
        List<String> idList = new ArrayList<>();
        this.selectChildListById(id, idList);

        idList.add(id);
        baseMapper.deleteBatchIds(idList);
    }

    /**
     * //根据用户id获取用户菜单
     *
     * @param id
     * @return
     */
    @Override
    public List<String> selectPermissionValueByUserId(String id) {

        List<String> selectPermissionValueList = null;
        if (this.isSysAdmin(id)) {
            //如果是系统管理员，获取所有权限
            selectPermissionValueList = baseMapper.selectAllPermissionValue();
        } else {
            selectPermissionValueList = baseMapper.selectPermissionValueByUserId(id);
        }
        return selectPermissionValueList;
    }

    @Override
    public List<JSONObject> selectPermissionByUserId(String userId) {
        List<Permission> selectPermissionList = null;
        if (this.isSysAdmin(userId)) {
            //如果是超级管理员，获取所有菜单
            selectPermissionList = baseMapper.selectList(null);
        } else {
            selectPermissionList = baseMapper.selectPermissionByUserId(userId);
        }

        List<Permission> permissionList = PermissionHelper.bulid(selectPermissionList);
        List<JSONObject> result = MemuHelper.bulid(permissionList);
        return result;
    }

    /**
     * 判断用户是否系统管理员
     *
     * @param userId
     * @return
     */
    private boolean isSysAdmin(String userId) {
        User user = userService.getById(userId);

        if (null != user && "admin".equals(user.getUsername())) {
            return true;
        }
        return false;
    }

    /**
     * 递归获取子节点
     *
     * @param id
     * @param idList
     */
    private void selectChildListById(String id, List<String> idList) {
        List<Permission> childList = baseMapper.selectList(new QueryWrapper<Permission>().eq("pid", id).select("id"));
        childList.stream().forEach(item -> {
            idList.add(item.getId());
            this.selectChildListById(item.getId(), idList);
        });
    }

    /**
     * 使用递归方法建菜单
     *
     * @param allPermissionList 所有菜单
     * @return
     */
    private static List<Permission> bulid(List<Permission> allPermissionList) {
        List<Permission> results = new ArrayList<>();
        allPermissionList.stream().forEach(permission -> {
            //找到pid为0的首菜单
            if ("0".equals(permission.getPid())) {
                permission.setLevel(1);
                results.add(findChildren(permission, allPermissionList));
            }
        });

        return results;
    }

    /**
     * 当前菜单在所有菜单中找子菜单 构建 层次结构菜单(dfs)
     *
     * @param permissionCurrent 当前菜单
     * @param allPermissionList 所有菜单
     * @return
     */
    private static Permission findChildren(Permission permissionCurrent, List<Permission> allPermissionList) {
        permissionCurrent.setChildren(new ArrayList<>());
        //某菜单的 pid = 当前菜单id 时, 就找到了子菜单
        allPermissionList.stream().forEach(permission -> {
            if (permission.getPid().equals(permissionCurrent.getId())) {
                //子菜单级别要比父菜单高1
                permission.setLevel(permissionCurrent.getLevel() + 1);
                if (permissionCurrent.getChildren() == null) {
                    permissionCurrent.setChildren(new ArrayList<>());
                }
                //子菜单继续递归找它的子菜单
                permissionCurrent.getChildren().add(findChildren(permission, allPermissionList));
            }
        });
        return permissionCurrent;
    }


    /**
     * 递归查询所有菜单
     *
     * @return
     */
    @Override
    public List<Permission> queryAllMenuGuli() {
        //1 查询菜单表所有数据
        QueryWrapper<Permission> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("id");
        List<Permission> permissionList = baseMapper.selectList(wrapper);
        //2 把查询所有菜单list集合按照要求进行封装
        List<Permission> resultList = bulidPermission(permissionList);

        return resultList;
    }

    /**
     * 找到顶层菜单,对下层进行封装
     * 把返回所有菜单list集合进行封装的方法(类似dfs)
     * 终止条件就是集合遍历完毕
     *
     * @param permissionList 所有菜单数据
     * @return
     */
    public static List<Permission> bulidPermission(List<Permission> permissionList) {
        //创建list集合，用于数据最终封装
        List<Permission> resultList = new ArrayList<>();
        //把所有菜单list集合遍历，得到顶层菜单 pid=0菜单，设置level是1
        permissionList.stream().forEach(permission -> {
            //找到顶层菜单pid=0
            if ("0".equals(permission.getPid())) {
                permission.setLevel(1);
                //根据顶层菜单，向里面进行查询子菜单，封装到resultList中
                resultList.add(selectChildren(permission, permissionList));
            }
        });
        return resultList;
    }

    /**
     * 在所有菜单数据中找到pid 与 父菜单 id相同的数据进行封装
     *
     * @param permissionParent 父菜单
     * @param permissionList   所有菜单数据
     * @return
     */
    private static Permission selectChildren(Permission permissionParent, List<Permission> permissionList) {
        //在所有菜单数据中找到pid 与 父菜单 id相同的数据
        permissionList.stream().forEach(permission -> {
            if (permission.getPid().equals(permissionParent.getId())) {
                //菜单级别要比父菜单级别高一级
                permission.setLevel(permissionParent.getLevel() + 1);
                if (permissionParent.getChildren() == null) {
                    permissionParent.setChildren(new ArrayList<>());
                }
                //继续向更深的一层进行封装(深度优先搜索)
                permissionParent.getChildren().add(selectChildren(permission, permissionList));
            }
        });
        //这里的父菜单已经完成子菜单的封装了
        return permissionParent;
    }

    /**
     * 递归删除菜单
     * 使用一个集合来保存要删除的菜单id
     * 递归查找所有要删除的子菜单id,加入集合中,最后一次性进行删除
     *
     * @param id
     */
    @Override
    public void removeChildByIdGuli(String id) {
        //使用一个集合来保存要删除的菜单id
        List<String> idList = new ArrayList<>();
        //把当前id封装到list里面
        idList.add(id);
        //递归查找所有要删除的子菜单id,加入集合中
        selectPermissionChildById(id, idList);

        //一次性删除
        baseMapper.deleteBatchIds(idList);
    }

    /**
     * 根据当前菜单id查到子菜单id加入删除id的集合中 (dfs)
     *
     * @param id     当前菜单的id
     * @param idList 保存要删除的菜单id
     */
    private void selectPermissionChildById(String id, List<String> idList) {
        QueryWrapper<Permission> wrapper = new QueryWrapper<>();
        wrapper.eq("pid", id);
        //只需要查id,提高效率
        wrapper.select("id");
        //查到的子菜单集合
        List<Permission> permissionList = baseMapper.selectList(wrapper);
        //在子菜单集合中继续递归dfs 查询要删除的子子菜单集合
        permissionList.stream().forEach(permission -> {
            //将要删除的id存放到集合
            idList.add(permission.getId());
            //继续递归dfs查询子子菜单
            selectPermissionChildById(permission.getId(), idList);
        });
    }

    /**
     * 给角色分配权限
     * 往角色-权限(菜单)关联表(acl_role_permission)中添加数据
     *
     * @param roleId
     * @param permissionIds
     */
    @Override
    public void saveRolePermissionRealtionShipGuli(String roleId, String[] permissionIds) {
        List<RolePermission> rolePermissionList = new ArrayList<>();
        for (String permissionId : permissionIds) {
            //将角色id,权限id封装成类
            RolePermission rolePermission = new RolePermission();
            rolePermission.setRoleId(roleId);
            rolePermission.setPermissionId(permissionId);
            //再把类加入集合
            rolePermissionList.add(rolePermission);
        }
        //最后批量添加
        boolean flag = rolePermissionService.saveBatch(rolePermissionList);
        if (!flag) {
            throw new ServerException("系统故障,为角色分配权限失败");
        }

       /* //roleId角色id
        //permissionId菜单id 数组形式
        //1 创建list集合，用于封装添加数据
        List<RolePermission> rolePermissionList = new ArrayList<>();
        //遍历所有菜单数组
        for (String perId : permissionIds) {
            //RolePermission对象
            RolePermission rolePermission = new RolePermission();
            rolePermission.setRoleId(roleId);
            rolePermission.setPermissionId(perId);
            //封装到list集合
            rolePermissionList.add(rolePermission);
        }
        //添加到角色菜单关系表
        rolePermissionService.saveBatch(rolePermissionList);*/
    }
}
